/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    spi.c
 * @brief   This file provides code for the configuration
 *          of the SPI instances.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
 /* USER CODE END Header */
 /* Includes ------------------------------------------------------------------*/
#include "spi.h"

#include "cmsis_os2.h"
#include "lcd.h"

#include "lvgl.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef handle_GPDMA1_Channel0;

volatile uint8_t *spi_data_pos = NULL;
volatile uint32_t spi_data_len = 0;
static volatile bool spi_dma_busy = false;

/* SPI2 init function */
void MX_SPI2_Init(void)
{

    /* USER CODE BEGIN SPI2_Init 0 */

    /* USER CODE END SPI2_Init 0 */

    SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = { 0 };

    /* USER CODE BEGIN SPI2_Init 1 */

    /* USER CODE END SPI2_Init 1 */
    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_MASTER;
    hspi2.Init.Direction = SPI_DIRECTION_1LINE;
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
    hspi2.Init.NSS = SPI_NSS_SOFT;
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi2.Init.CRCPolynomial = 0x7;
    hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    hspi2.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
    hspi2.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
    if ( HAL_SPI_Init(&hspi2) != HAL_OK ) {
        Error_Handler();
    }
    HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
    HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP1_GPDMA_CH0_TCF_TRG;
    HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
    if ( HAL_SPIEx_SetConfigAutonomousMode(&hspi2, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK ) {
        Error_Handler();
    }
    /* USER CODE BEGIN SPI2_Init 2 */

    /* USER CODE END SPI2_Init 2 */
}

void HAL_SPI_MspInit(SPI_HandleTypeDef *spiHandle)
{

    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
    if ( spiHandle->Instance == SPI2 ) {
        /* USER CODE BEGIN SPI2_MspInit 0 */

        /* USER CODE END SPI2_MspInit 0 */

        /** Initializes the peripherals clock
         */
        PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
        PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_SYSCLK;
        if ( HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK ) {
            Error_Handler();
        }

        /* SPI2 clock enable */
        __HAL_RCC_SPI2_CLK_ENABLE();

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**SPI2 GPIO Configuration
        PB13     ------> SPI2_SCK
        PB15     ------> SPI2_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_15;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* SPI2 DMA Init */
         /* GPDMA1_REQUEST_SPI2_TX Init */
        handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
        handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_SPI2_TX;
        handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
        handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_PERIPH;
        handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_INCREMENTED;
        handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
        handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
        handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_SRC_DATAWIDTH_BYTE;
        handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT;
        handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
        handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
        handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
        handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
        handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
        if ( HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK ) {
            Error_Handler();
        }

        __HAL_LINKDMA(spiHandle, hdmatx, handle_GPDMA1_Channel0);

        if ( HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_PRIV) != HAL_OK ) {
            Error_Handler();
        }

        /* SPI2 interrupt Init */
        HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(SPI2_IRQn);
    }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef *spiHandle)
{

    if ( spiHandle->Instance == SPI2 ) {
        /* USER CODE BEGIN SPI2_MspDeInit 0 */

        /* USER CODE END SPI2_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_SPI2_CLK_DISABLE();

        /**SPI2 GPIO Configuration
        PB13     ------> SPI2_SCK
        PB15     ------> SPI2_MOSI
        */
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13 | GPIO_PIN_15);

        /* SPI2 DMA DeInit */
        HAL_DMA_DeInit(spiHandle->hdmatx);

        /* SPI2 interrupt Deinit */
        HAL_NVIC_DisableIRQ(SPI2_IRQn);
    }
}

/**
 * @brief 启动SPI DMA数据传输
 * @param data 要传输的数据指针
 * @param len 数据长度
 * @return HAL_StatusTypeDef 传输启动状态
 */
HAL_StatusTypeDef spi_dma_push_data(const uint8_t *data, uint32_t len)
{
    // 参数检查
    if ( data == NULL || len == 0 ) {
        return HAL_ERROR;
    }

    // 检查是否有传输正在进行
    if ( true == spi_dma_busy ) {
        return HAL_BUSY;
    }

    // 保存传输信息
    spi_data_pos = ( uint8_t * ) data;
    spi_data_len = len;

    // 计算第一包大小（不超过65535）
    uint16_t chunk_size = (len > 65535) ? 65535 : ( uint16_t ) len;
    spi_data_len -= chunk_size;
    spi_data_pos += chunk_size;

    // 启动首次传输
    spi_dma_busy = true;
    return HAL_SPI_Transmit_DMA(&hspi2, data, chunk_size);
}

bool is_spi_dma_busy(void)
{
    return spi_dma_busy;
}

/**
 * @brief SPI DMA传输完成回调
 * @param hspi SPI句柄指针
 */
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if ( hspi == &hspi2 ) {
       // 检查是否还有数据需要传输
        if ( spi_data_len > 0 ) {
            // 计算下一包大小
            uint16_t chunk_size = (spi_data_len > 65535) ? 65535 : ( uint16_t ) spi_data_len;

            // 启动下一次传输
            HAL_SPI_Transmit_DMA(hspi, (const uint8_t*)spi_data_pos, chunk_size);

            // 更新位置和剩余长度
            spi_data_pos += chunk_size;
            spi_data_len -= chunk_size;
        } else {
            // 传输完成，清理状态
            spi_data_pos = NULL;
            spi_dma_busy = false;

            extern void lv_custom_flush_ready(void);
            lv_custom_flush_ready(); 
        }
    }
}

void lcd_write_area_buf( uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t* color)
{
    extern lcd lcd_desc;
	uint16_t copy_len = (yend - ysta + 1) * (xend - xsta + 1) * 2;

	if (NULL == color) {
		return;
	}

    while (spi_dma_busy) {
        osDelay(1);
    }

	//LCD_Address_Set( xsta, ysta, xend, yend);//设置显示范围
    lcd_set_address(&lcd_desc, xsta, ysta, xend, yend);
	//lcd_spi_cs_level(0);
    // lcd_spi_dma_busy = true;
	// HAL_SPI_Transmit_DMA( &hspi1, (uint8_t*)(color), (copy_len));

    lcd_io_dc((&lcd_desc)->io, 1);

    spi_dma_push_data((uint8_t*)(color), copy_len);
}
